package com.yupi.yangoj.judge;

import cn.hutool.json.JSONUtil;
import com.yupi.yangoj.common.ErrorCode;
import com.yupi.yangoj.exception.BusinessException;
import com.yupi.yangoj.judge.codesandbox.CodeSandBox;
import com.yupi.yangoj.judge.codesandbox.CodeSandBoxFactory;
import com.yupi.yangoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.yupi.yangoj.judge.codesandbox.model.ExecuteCodeResponse;
import com.yupi.yangoj.judge.strategy.JudgeContext;
import com.yupi.yangoj.model.dto.question.JudgeCase;
import com.yupi.yangoj.judge.codesandbox.model.JudgeInfo;
import com.yupi.yangoj.model.entity.Question;
import com.yupi.yangoj.model.entity.QuestionSubmit;
import com.yupi.yangoj.model.enums.QuestionSubmitStatusEnum;
import com.yupi.yangoj.service.QuestionService;
import com.yupi.yangoj.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionService questionService;
    @Resource
    private QuestionSubmitService questionSubmitService;
    @Resource
    private JudgeManager judgeManager;
    @Value("${codesandbox.type}")
    private String type;


    /**
     * 判题业务功能（核心！！！！！！）
     *
     * @param questionSubmitId 题目提交id
     * @return
     */
    @Override
    public QuestionSubmit doSubmit(long questionSubmitId) {
        //获取题目提交信息（提交代码，编程语言），题目信息
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionService.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }

        //判断题目提交状态是否为等待中，如果不是，就不用执行了
        if (!Objects.equals(questionSubmit.getStatus(), QuestionSubmitStatusEnum.WAITING.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");
        }

        //如果是等待中状态，则进行判题，同时修改状态
        QuestionSubmit questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.RUNING.getValue());
        questionSubmitUpdate.setId(questionSubmitId);
        //更新状态
        boolean update = questionSubmitService.updateById(questionSubmitUpdate);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新异常");
        }

        //调用代码沙箱
        String code = questionSubmit.getCode();     //用户提交代码
        String judgeCaseStr = question.getJudgeCase();   //题目的输入输出用例（json数组）
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        //得到题目全部的输入用例
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        String language = questionSubmit.getLanguage();    //提交的编程语言

        //拿到代码沙箱
        CodeSandBox codeSandBox = CodeSandBoxFactory.newInstance(type);
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList).build();
        //执行代码
        ExecuteCodeResponse executeCodeResponse = codeSandBox.executeCode(executeCodeRequest);
        List<String> outputList = executeCodeResponse.getOutputList();    //执行结果的输出用例

        //拿到执行结果，进行判题（输出用例的数量，输出用例是否与预期相等，执行是否出现异常），然后设置题目的判题状态与信息
        JudgeInfo judgeInfo = new JudgeInfo();
        if (executeCodeResponse.getStatus() != 1) {
            //返回的executeCodeResponse的信息状态错误，直接设置message
            String message = executeCodeResponse.getMessage();
            int index = message.lastIndexOf(":");     //截取一下关键信息
            String substring = message.substring(index + 2);
            judgeInfo.setMessage(substring);
        } else {
            JudgeContext judgeContext = new JudgeContext();
            judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
            judgeContext.setInputList(inputList);
            judgeContext.setOutputList(outputList);
            judgeContext.setJudgeCaseList(judgeCaseList);
            judgeContext.setQuestion(question);
            judgeContext.setQuestionSubmit(questionSubmit);

            //返回的executeCodeResponse信息状态正确，开始判题，拿到判题结果
            judgeInfo = judgeManager.doJudge(judgeContext);
        }

        //修改数据库判题结果
        questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        if (executeCodeResponse.getStatus() != 1) {
            questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.FAILED.getValue());
        }
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        //更新题目提交的状态
        update = questionSubmitService.updateById(questionSubmitUpdate);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新异常");
        }
        //判题结果成功的话，修改该题目的通过数
        if ("Accepted".equals(judgeInfo.getMessage())) {
            question.setAcceptedNum(question.getAcceptedNum() + 1);
            boolean update1 = questionService.updateById(question);
            if (!update1) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目通过数更新异常");
            }
        }

        //返回当前提交题目的最新数据
        QuestionSubmit result = questionSubmitService.getById(questionSubmitId);
        return result;
    }


}
